package ai.people.platform.oss.service.impl;

import ai.people.netmon.framework.domain.oss.vo.UploadVO;
import ai.people.netmon.framework.exception.enums.FileExceptionEnum;
import ai.people.netmon.framework.utils.AssertUtils;
import ai.people.netmon.utils.StringPool;
import ai.people.netmon.utils.localdateUtil.DateTimeFormatterUtil;
import ai.people.platform.oss.config.OssClientFactoryBean;
import ai.people.platform.oss.properties.AliOssProperties;
import ai.people.platform.oss.service.OssStorageService;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.OSSObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Objects;

/**
 * oss服务
 *
 * @author yuanqinglong
 * @date 2022/4/28 17:35
 */
@Slf4j
@Service("aliOssStorage")
@RequiredArgsConstructor
public class AliOssStorageServiceImpl implements OssStorageService {

    /**
     * 日志记录器
     */
    private final Logger logger = LoggerFactory.getLogger(AliOssStorageServiceImpl.class);

    /**
     * 阿里oss属性
     */
    private final AliOssProperties aliOssProperties;

    /**
     * oss客户工厂bean
     */
    private final OssClientFactoryBean ossClientFactoryBean;



    /**
     * 上传图片
     *
     * @param multipartFile 多部分文件
     * @return {@link UploadVO}
     * @throws IOException 异常
     */
    @Override
    public UploadVO uploadPicture(MultipartFile multipartFile) throws Exception {
        String fileName = this.createPictureName(multipartFile.getOriginalFilename());
        return this.getUploadVO(multipartFile.getInputStream(), fileName);
    }

    /**
     * 上传文件
     *
     * @param multipartFile 多部分文件
     * @return {@link UploadVO}
     * @throws Exception 异常
     */
    @Override
    public UploadVO uploadFile(MultipartFile multipartFile) throws Exception {
        String fileName = this.createFileName(multipartFile.getOriginalFilename());
        return this.getUploadVO(multipartFile.getInputStream(), fileName);
    }

    /**
     * 上传
     *
     * @param inputStream 输入流
     * @param fileName    文件名称
     * @return {@link UploadVO}
     * @throws Exception 异常
     */
    public UploadVO getUploadVO(InputStream inputStream, String fileName) throws Exception {
        String url = aliOssProperties.getDirectoryPrefix() + StringPool.SLASH + fileName;
        OSS ossClient = ossClientFactoryBean.getObject();
        logger.info("{} {} starting update file : {}", ossClient, DateTimeFormatterUtil.currentDateTime(), url);
        assert Objects.nonNull(ossClient);
        ossClient.putObject(aliOssProperties.getBucketName(), url, inputStream);
        logger.info("{} completed update file : {}", DateTimeFormatterUtil.currentDateTime(), url);
        return UploadVO.builder().build().setName(fileName);
    }


    /**
     * 下载
     *
     * @param fileName 文件名称
     */
    @Override
    public void write(String fileName, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        OSSObject ossResult = getOssObject(fileName);
        this.setPictureResponseHeaders(httpServletRequest, httpServletResponse, fileName);
        // 调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
        // 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
        try (OutputStream outputStream = httpServletResponse.getOutputStream(); InputStream ossResultObjectContent = ossResult.getObjectContent()) {
            outputStream.write(ossResultObjectContent.readAllBytes());
        }

    }

    private OSSObject getOssObject(String fileName) throws Exception {
        OSS ossClient = ossClientFactoryBean.getObject();
        String url = aliOssProperties.getDirectoryPrefix() + StringPool.SLASH + fileName;
        logger.info("{} {} starting obtain file : {}", ossClient, DateTimeFormatterUtil.currentDateTime(), url);
        assert Objects.nonNull(ossClient);
        boolean objectExist = ossClient.doesObjectExist(aliOssProperties.getBucketName(), url);
        AssertUtils.isTrue(objectExist, FileExceptionEnum.FILE_DOES_NOT_EXIST);
        return ossClient.getObject(aliOssProperties.getBucketName(), url);
    }

    /**
     * 写文件
     *
     * @param fileName            文件名称
     * @param httpServletRequest  http servlet请求
     * @param httpServletResponse http servlet响应
     */
    @Override
    public void writeFile(String fileName, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        OSSObject ossResult = getOssObject(fileName);
        this.setFileResponseHeaders(httpServletRequest, httpServletResponse, fileName);
        // 调用ossObject.getObjectContent获取文件输入流，可读取此输入流获取其内容。
        // 数据读取完成后，获取的流必须关闭，否则会造成连接泄漏，导致请求无连接可用，程序无法正常工作。
        try (OutputStream outputStream = httpServletResponse.getOutputStream(); InputStream ossResultObjectContent = ossResult.getObjectContent()) {
            outputStream.write(ossResultObjectContent.readAllBytes());
        }
    }
}
